package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/tealeg/xlsx"
)

// 定义嵌套映射类型
type ConfigMap map[interface{}]interface{}

// Excel解析配置
type SheetConfig struct {
	ExportType string     // tiny/base
	KeyCount   int        // 主键数量
	OutputPath string     // 输出路径
	Header     string     // 文件头
	Footer     string     // 文件尾
	Annotation []string   // 注释
	Parameter  []string   //导出参数
	FieldNames []string   //字段名
	DataRows   [][]string //数据
}

func Transform(app *AppData, excelFile string) []error {
	var errs []error // 初始化错误切片
	// 打开Excel文件
	xlFile, err := xlsx.OpenFile(excelFile)
	if err != nil {
		log.Fatal("打开Excel文件失败:", err)
		return append(errs, fmt.Errorf("打开Excel文件失败: %s", err))
	}
	segments := strings.Split(excelFile, "\\") // 注意Windows路径使用反斜杠
	fileName := segments[len(segments)-1]
	// 遍历所有工作表
	for _, sheet := range xlFile.Sheets {
		if sheet.Name == "Sheet1" { // 跳过空表
			continue
		}

		// 解析工作表配置
		config, err := parseSheetConfig(sheet)
		if config == nil {
			errs = append(errs, err)
			continue
		}

		// 生成配置文件
		ret := generateConfigFiles(config, app, fileName, sheet.Name)
		errs = append(errs, ret)
	}

	return errs
}

func ReplaceByString(strArray []string) []string {
	// 移除所有换行符，包括\r\n和\n，但不包括单个的\r（如果需要）
	re := regexp.MustCompile(`\r?\n`) // \r? 表示\r可有可无，紧跟一个\n表示换行符可能是\n或\r\n中的一种形式
	for i, str := range strArray {
		strArray[i] = re.ReplaceAllString(str, "")
	}

	return strArray
}

// 解析工作表配置
func parseSheetConfig(sheet *xlsx.Sheet) (*SheetConfig, error) {
	config := &SheetConfig{
		FieldNames: make([]string, 0),
		DataRows:   make([][]string, 0),
		Annotation: make([]string, 0),
		Parameter:  make([]string, 0),
	}

	// 解析元数据行
	for rowIndex, row := range sheet.Rows {
		if rowIndex < 4 { // 前5行是元数据
			cells := row.Cells
			if len(cells) < 4 {
				continue
			}

			switch cells[0].String() {
			case "导出类型":
				config.ExportType = cells[1].String()
			case "导出文件":
				config.OutputPath = cells[1].String()
			case "key数量":
				config.KeyCount, _ = strconv.Atoi(cells[1].String())
			}
			switch cells[3].String() {
			case "导出文件头":
				config.Header = strings.TrimSpace(cells[4].String())
			case "导出文件尾":
				config.Footer = strings.TrimSpace(cells[4].String())
			}
		} else { // 数据行
			var dataRow []string
			for _, cell := range row.Cells {
				dataRow = append(dataRow, strings.TrimSpace(cell.String()))
			}
			if config.ExportType == "base" {
				// 第一行数据作为注释名
				if rowIndex == 4 {
					config.Annotation = ReplaceByString(dataRow)
				}
				// 第一行数据作为导出参数
				if rowIndex == 5 {
					config.Parameter = dataRow
				}
				// 第一行数据作为字段名
				if rowIndex == 6 {
					config.FieldNames = dataRow
				}
				if rowIndex > 6 {
					config.DataRows = append(config.DataRows, dataRow)
				}
			} else {
				if len(dataRow) >= 3 {
					config.DataRows = append(config.DataRows, dataRow)
				}
			}
		}
	}
	return config, nil
}

// 生成配置文件
func generateConfigFiles(config *SheetConfig, app *AppData, fileName string, sheetName string) error {
	// 根据类型选择生成器
	switch config.ExportType {
	case "tiny":
		return generateTinyConfig(config, app, fileName, sheetName)
	case "base":
		return generateBaseConfig(config, app, fileName, sheetName)
	default:
		log.Printf("未知的导出类型: %s", config.ExportType)
	}
	return nil
}

func extractKey(input string) (string, error) {
	// 步骤 1：使用正则表达式移除所有空白字符
	re := regexp.MustCompile(`\s+`)
	cleanStr := re.ReplaceAllString(input, "")

	// 步骤 2：查找等号位置
	eqIndex := strings.Index(cleanStr, "=")
	if eqIndex == -1 {
		return "", fmt.Errorf("未找到等号")
	}

	// 步骤 3：提取等号前内容
	return cleanStr[:eqIndex], nil
}

// 生成JSON格式配置
func generateJSONConfig(configs *SheetConfig, fileName string, sheetName string) (map[string]interface{}, error) {
	dataMap := make(map[string]interface{})
	dataMap["A__comment"] = fmt.Sprintf("Generated from xlsx: %s, sheet: %s", fileName, sheetName)

	configData := make(map[string]string)
	isHasData := false
	for i := 1; i < len(configs.DataRows); i++ {
		entry := configs.DataRows[i]
		if len(entry) < 4 || entry[1] == "" || entry[2] == "" || entry[3] == "" {
			continue
		}

		isExport := strings.ToLower(entry[1]) == "c" || strings.ToLower(entry[1]) == "sc"
		if isExport {
			isHasData = true
			configData[entry[2]] = entry[3]
		}
	}
	key, _ := extractKey(configs.Header)
	dataMap[key] = configData
	if !isHasData {
		return make(map[string]interface{}), nil
	}
	return dataMap, nil
}

// 生成tiny类型配置
func generateTinyConfig(configs *SheetConfig, app *AppData, fileName string, sheetName string) error {
	var sb strings.Builder
	sb.WriteString(fmt.Sprintf(" --xlsx文件名字::%s sheet工作表名:%s\n\n", fileName, sheetName))
	sb.WriteString(fmt.Sprintf("local %s\t\n", configs.Header))
	isHasData := false
	parts := strings.SplitN(configs.Header, "=", 2)
	if len(parts) < 2 {
		fmt.Println("无效的配置格式")
	}

	// 提取并清理左侧字符串
	leftPart := strings.TrimSpace(parts[0])
	re := regexp.MustCompile(`\r?\n`) // \r? 表示\r可有可无，紧跟一个\n表示换行符可能是\n或\r\n中的一种形式
	// 填充数据
	for i := 1; i < len(configs.DataRows); i++ {
		entry := configs.DataRows[i]
		if len(entry) < 3 || entry[1] == "" || entry[2] == "" {
			continue
		}
		isExport := strings.ToLower(entry[1]) == "s" || strings.ToLower(entry[1]) == "sc"

		if entry[3] != "" && isExport {
			isHasData = true
			if entry[0] != "" {
				sb.WriteString(fmt.Sprintf("\t%s = %s, -- %s\n", entry[2], entry[3], re.ReplaceAllString(entry[0], "")))
			} else {
				sb.WriteString(fmt.Sprintf("\t%s = %s, \n", entry[2], entry[3]))
			}
		}

	}

	sb.WriteString(fmt.Sprintf("}\n return %s", leftPart))
	luaStr := sb.String()
	if !isHasData {
		luaStr = ""
	}

	jsonData, _ := generateJSONConfig(configs, fileName, sheetName)
	jsonContent, err := json.MarshalIndent(jsonData, "", "  ")
	if err != nil {
		return fmt.Errorf("解析json失败: %w", err)
	}
	return writeFiles(configs.OutputPath, app.config.InputLua, app.config.InputJson, luaStr, string(jsonContent))
}

func generateJsonBaseConfig(configs *SheetConfig, fileName string, sheetName string) []byte {
	// 创建JSON数据结构
	jsonData := make(map[string]interface{})
	configData := make(map[string]interface{})
	configData["A__comment"] = fmt.Sprintf("Generated from xlsx: %s, sheet: %s", fileName, sheetName)
	isHasData := false
	for i := 0; i < len(configs.DataRows); i++ {
		entry := configs.DataRows[i]
		if len(entry) <= 1 || entry[1] == "" {
			continue
		}
		// 处理JSON生成
		if configs.KeyCount <= 0 {
			continue
		}
		keys := make([]string, configs.KeyCount)
		validKeys := true
		for k := 0; k < configs.KeyCount; k++ {
			if k+1 >= len(entry) || entry[k+1] == "" {
				validKeys = false
				break
			}
			keys[k] = entry[k+1]
		}
		if !validKeys {
			continue
		}

		currentMap := jsonData
		// 构建嵌套结构
		for ki := 0; ki < configs.KeyCount-1; ki++ {
			key := keys[ki]
			if _, exists := currentMap[key]; !exists {
				currentMap[key] = make(map[string]interface{})
			}
			nextMap, ok := currentMap[key].(map[string]interface{})
			if !ok {
				// 类型错误，重新创建
				nextMap = make(map[string]interface{})
				currentMap[key] = nextMap
			}
			currentMap = nextMap
		}
		lastKey := keys[configs.KeyCount-1]

		// 收集字段
		fields := make(map[string]interface{})
		for pk, pv := range entry {
			if pk == 0 || pv == "" {
				continue
			}
			if pk >= len(configs.Parameter) || pk >= len(configs.FieldNames) {
				continue
			}
			param := strings.ToLower(configs.Parameter[pk])
			if param == "c" || param == "sc" {
				fieldName := configs.FieldNames[pk]
				fields[fieldName] = pv
				isHasData = true
			}
		}

		currentMap[lastKey] = fields
	}
	if !isHasData {
		return []byte("")
	}
	title, _ := extractKey(configs.Header)
	configData[title] = jsonData
	// 生成JSON内容
	jsonContent, err := json.MarshalIndent(configData, "", "  ")
	if err != nil {
		jsonContent = []byte("")
	}

	return jsonContent
}

// 生成base类型配置
func generateBaseConfig(configs *SheetConfig, app *AppData, fileName string, sheetName string) error {
	var sb strings.Builder
	sb.WriteString(fmt.Sprintf(" --xlsx文件名字::%s sheet工作表名:%s\n\n", fileName, sheetName))
	sb.WriteString(fmt.Sprintf("local %s\t\n", configs.Header))
	parts := strings.SplitN(configs.Header, "=", 2)
	if len(parts) < 2 {
		return fmt.Errorf("无效的配置格式")
	}

	// 提取并清理左侧字符串
	leftPart := strings.TrimSpace(parts[0])

	isHasData := false
	if configs.KeyCount == 1 {
		for i := 0; i < len(configs.DataRows); i++ {
			entry := configs.DataRows[i]
			if entry == nil {
				continue
			}

			//判断没有key的不导出
			if len(entry) <= 1 || entry[1] == "" {
				break
			}

			if configs.ExportType == "base" && configs.KeyCount == 1 {
				sb.WriteString(fmt.Sprintf("  [%s] = {\n", entry[1]))
				for pk, pv := range entry {
					if pk == 0 || pv == "" {
						continue
					}
					if len(configs.Parameter) <= pk || len(configs.FieldNames) <= pk {
						continue
					}
					if strings.ToLower(configs.Parameter[pk]) == "s" || strings.ToLower(configs.Parameter[pk]) == "sc" {
						isHasData = true
						sb.WriteString(fmt.Sprintf("\t\t%s = %s, -- %s\n", configs.FieldNames[pk], pv, configs.Annotation[pk]))
					}
				}

				sb.WriteString("    },\n")

			}
		}
	} else {

		// 状态跟踪器
		type levelState struct {
			currentKey string
			opened     bool
		}
		stateStack := make([]levelState, configs.KeyCount) // 记录各层状态
		for rowIdx, entry := range configs.DataRows {
			// 跳过无效数据行
			if len(entry) < configs.KeyCount+1 {
				log.Printf("第%d行数据列不足,跳过", rowIdx+1)
				continue
			}

			//判断没有key的不导出
			if len(entry) <= 1 || entry[1] == "" {
				break
			}

			// 提取当前键序列
			currentKeys := make([]string, configs.KeyCount)
			validKeys := true
			for k := 0; k < configs.KeyCount; k++ {
				currentKeys[k] = strings.TrimSpace(entry[k+1])
				if currentKeys[k] == "" {
					validKeys = false
					break
				}
			}
			if !validKeys {
				continue
			}

			// 层级变化检测
			needCloseLevel := 0
			for l := 0; l < configs.KeyCount; l++ {
				if stateStack[l].currentKey != currentKeys[l] {
					needCloseLevel = configs.KeyCount - l
					break
				}
			}

			// 关闭变化的层级
			for l := 0; l < needCloseLevel; l++ {
				closeLevel := configs.KeyCount - l - 1
				if stateStack[closeLevel].opened {
					sb.WriteString(strings.Repeat("\t", closeLevel+1) + "},\n")
					stateStack[closeLevel].opened = false
				}
			}

			// 打开新层级
			for l := 0; l < configs.KeyCount; l++ {
				if stateStack[l].currentKey != currentKeys[l] || !stateStack[l].opened {
					// 关闭前先打开父级
					for parent := 0; parent < l; parent++ {
						if !stateStack[parent].opened {
							sb.WriteString(strings.Repeat("\t", parent) + "[" + stateStack[parent].currentKey + "] = {\n")
							stateStack[parent].opened = true
						}
					}

					// 打开当前层级
					sb.WriteString(strings.Repeat("\t", l+1) + "[" + currentKeys[l] + "] = {\n")
					stateStack[l] = levelState{currentKey: currentKeys[l], opened: true}
				}
			}

			// 写入字段数据
			indent := strings.Repeat("\t", configs.KeyCount+1)
			for col := configs.KeyCount + 1; col < len(entry); col++ {
				if col >= len(configs.Parameter) || col >= len(configs.FieldNames) {
					continue
				}

				paramType := strings.ToLower(configs.Parameter[col])
				if paramType == "s" || paramType == "sc" {
					fieldName := configs.FieldNames[col]
					fieldValue := entry[col]
					isHasData = true
					if fieldValue != "" {
						sb.WriteString(fmt.Sprintf("%s%s = %s, -- %s\n",
							indent,
							fieldName,
							fieldValue,
							configs.Annotation[col]))
					}

				}
			}

		}

		// 闭合所有打开的层级
		for l := configs.KeyCount - 1; l >= 0; l-- {
			if stateStack[l].opened {
				sb.WriteString(strings.Repeat("\t", l+1) + "}\n")
			}
		}

	}
	sb.WriteString(fmt.Sprintf("}\n return %s", leftPart))
	luaStr := sb.String()
	if !isHasData {
		luaStr = ""
	}
	// 生成JSON
	jsonContent := generateJsonBaseConfig(configs, fileName, sheetName)
	return writeFiles(configs.OutputPath, app.config.InputLua, app.config.InputJson, luaStr, string(jsonContent))

}

func splitPath(fullPath string) (dir string, fileName string) {
	// 统一转换为系统路径分隔符（兼容 Windows/Linux）
	normalized := filepath.FromSlash(fullPath)
	dir = filepath.Dir(normalized)
	fileName = filepath.Base(normalized)
	return
}

// 写入文件
func writeFiles(outputPath, outputLuaDir, outputJsonDir, luaContent, jsonContent string) error {

	baseName := strings.TrimSuffix(filepath.Base(outputPath), ".config")
	LuaPath := fmt.Sprintf("%s/%s", outputLuaDir, outputPath)
	dir, _ := splitPath(LuaPath)
	if luaContent != "" {
		// 创建目录（如果不存在）
		if err := os.MkdirAll(dir, 0755); err != nil {
			log.Printf("lua目录创建失败: %v", err.Error())
			return fmt.Errorf("lua目录创建失败: %s -  %w", dir, err)
		}

		// 拼接最终文件路径
		targetPath := filepath.Join(dir, baseName+".lua")

		if err := os.WriteFile(targetPath, []byte(luaContent), 0644); err != nil {
			if strings.Contains(err.Error(), "being used by another process") {
				log.Printf("文件被占用，请检查防病毒软件或其他进程是否锁定了 %s", targetPath)
			}
			log.Printf("写入Lua文件失败: %s", targetPath)
			return fmt.Errorf("写入Lua文件失败: %w", err)
		}
	}
	if jsonContent != "" {
		path := fmt.Sprintf("%s/%s", outputJsonDir, outputPath)
		dir, _ = splitPath(path)
		// 创建目录（如果不存在）
		if err := os.MkdirAll(dir, 0755); err != nil {
			log.Printf("josn目录创建失败: %v", err.Error())
			return fmt.Errorf("json目录创建失败:%s- %w", dir, err)
		}
		// 写入JSON 暂时不实现
		jsonPath := filepath.Join(dir, baseName+".json")

		if err := os.WriteFile(jsonPath, []byte(jsonContent), 0644); err != nil {
			log.Printf("写入JSON文件失败: %s -%s", jsonPath, err.Error())
			return fmt.Errorf("写入JSON文件失败: %s -%w", jsonPath, err)
		}
	}

	return nil
}
